package com.stars.easyms.datasource.manual;

import com.stars.easyms.datasource.batch.BatchCommit;
import com.stars.easyms.datasource.EasyMsDataSourceFactory;
import com.stars.easyms.datasource.EasyMsMultiDataSource;
import com.stars.easyms.datasource.annotation.EasyMsRepository;
import com.stars.easyms.datasource.interceptor.EasyMsPageInterceptor;
import com.stars.easyms.datasource.interceptor.EasyMsQueryInterceptor;
import com.stars.easyms.datasource.interceptor.EasyMsUpdateInterceptor;
import com.stars.easyms.datasource.pointcut.FixedDataSourceMethodPointcutAdvisor;
import com.stars.easyms.datasource.pointcut.FixedDataSourceTypePointcutAdvisor;
import com.stars.easyms.datasource.pointcut.SpecifyDataSourceMethodPointcutAdvisor;
import com.stars.easyms.datasource.pointcut.SpecifyDataSourceTypePointcutAdvisor;
import com.stars.easyms.datasource.properties.EasyMsPropertiesHelper;
import com.stars.easyms.datasource.mybatis.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <p>className: EasyMsManualBeanFactory</p>
 * <p>description: 手动创建bean工厂类</p>
 *
 * @author guoguifang
 * @version 1.2.2
 * @date 2019-07-16 14:13
 */
@Slf4j
final class EasyMsManualBeanFactory {

    private ConfigurableApplicationContext applicationContext;

    private EasyMsMultiDataSource easyMsMultiDataSource;

    private EasyMsMybatisConfiguration easyMsMybatisConfiguration;

    private EasyMsPageInterceptor easyMsPageInterceptor;

    private EasyMsQueryInterceptor easyMsQueryInterceptor;

    private EasyMsUpdateInterceptor easyMsUpdateInterceptor;

    private EasyMsSqlSessionFactory easyMsSqlSessionFactory;

    EasyMsMultiDataSource easyMsMultiDataSource() {
        this.easyMsMultiDataSource = applicationContext.getBean(EasyMsDataSourceFactory.class).createDataSource();
        return this.easyMsMultiDataSource;
    }

    EasyMsMybatisConfiguration easyMsMybatisConfiguration() {
        this.easyMsMybatisConfiguration = new EasyMsMybatisConfiguration();
        return this.easyMsMybatisConfiguration;
    }

    EasyMsPageInterceptor easyMsPageInterceptor() {
        this.easyMsPageInterceptor = new EasyMsPageInterceptor(this.easyMsMybatisConfiguration, this.easyMsMultiDataSource);
        this.easyMsPageInterceptor.setProperties(EasyMsPropertiesHelper.getEasyMsPageHelperProperties().getProperties());
        return this.easyMsPageInterceptor;
    }

    EasyMsSqlSessionFactory easyMsSqlSessionFactory() {
        EasyMsSqlSessionFactoryBean sqlSessionFactoryBean = new EasyMsSqlSessionFactoryBean(this.easyMsMybatisConfiguration);
        // 指定数据源
        sqlSessionFactoryBean.setDataSource(this.easyMsMultiDataSource);
        // 指定拦截器及分页插件
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.add(this.easyMsPageInterceptor);
        interceptors.add(this.easyMsUpdateInterceptor);
        interceptors.add(this.easyMsQueryInterceptor);
        sqlSessionFactoryBean.setPlugins(interceptors.toArray(new Interceptor[0]));
        // 指定基包
        sqlSessionFactoryBean.setTypeAliasesPackage(EasyMsPropertiesHelper.getEasyMsMybatisProperties().getTypeAliasesPackage());
        List<Resource> resourceList = new ArrayList<>();
        for (String mapperLocation : EasyMsPropertiesHelper.getEasyMsMybatisProperties().getMapperLocations()) {
            Resource[] resources = new Resource[0];
            try {
                resources = new PathMatchingResourcePatternResolver().getResources(mapperLocation);
            } catch (IOException e) {
                log.error("Get Resource [{}] fail!", mapperLocation, e);
            }
            resourceList.addAll(Arrays.asList(resources));
        }
        // 指定xml文件位置
        sqlSessionFactoryBean.setMapperLocations(resourceList.toArray(new Resource[0]));
        try {
            this.easyMsSqlSessionFactory = new EasyMsSqlSessionFactory(sqlSessionFactoryBean.getObject());
        } catch (Exception e) {
            throw new IllegalStateException("Get SqlSessionFactory bean fail!", e);
        }
        return this.easyMsSqlSessionFactory;
    }

    EasyMsSqlSessionTemplate easyMsSqlSessionTemplate() {
        return new EasyMsSqlSessionTemplate(this.easyMsSqlSessionFactory);
    }

    EasyMsMapperScannerConfigurer easyMsMapperScannerConfigurer() {
        EasyMsMapperScannerConfigurer mapperScannerConfigurer = new EasyMsMapperScannerConfigurer(applicationContext);
        mapperScannerConfigurer.setSqlSessionTemplateBeanName("easyMsSqlSessionTemplate");
        mapperScannerConfigurer.setBasePackage(EasyMsPropertiesHelper.getEasyMsMybatisProperties().getTypeAliasesPackage());
        mapperScannerConfigurer.setAnnotationClass(EasyMsRepository.class);
        return mapperScannerConfigurer;
    }

    FixedDataSourceTypePointcutAdvisor fixedDataSourceTypePointcutAdvisor() {
        return new FixedDataSourceTypePointcutAdvisor();
    }

    FixedDataSourceMethodPointcutAdvisor fixedDataSourceMethodPointcutAdvisor() {
        return new FixedDataSourceMethodPointcutAdvisor();
    }

    SpecifyDataSourceTypePointcutAdvisor specifyDataSourceTypePointcutAdvisor() {
        return new SpecifyDataSourceTypePointcutAdvisor(this.easyMsMultiDataSource);
    }

    SpecifyDataSourceMethodPointcutAdvisor specifyDataSourceMethodPointcutAdvisor() {
        return new SpecifyDataSourceMethodPointcutAdvisor(this.easyMsMultiDataSource);
    }

    EasyMsQueryInterceptor easyMsQueryInterceptor() {
        this.easyMsQueryInterceptor = new EasyMsQueryInterceptor(this.easyMsMultiDataSource);
        return this.easyMsQueryInterceptor;
    }

    EasyMsUpdateInterceptor easyMsUpdateInterceptor() {
        this.easyMsUpdateInterceptor = new EasyMsUpdateInterceptor(this.easyMsMultiDataSource);
        return this.easyMsUpdateInterceptor;
    }

    BatchCommit batchCommitDAO() {
        return new BatchCommit(this.easyMsMultiDataSource, this.easyMsSqlSessionFactory);
    }

    EasyMsManualBeanFactory(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}